<?php

namespace common\validators;

use Yii;

/**
 * IdcardValidator validates that the attribute value is a valid idcard number.
 *
 * @author emhome <emhome@163.com>
 * @since 2.0
 */
class IdcardValidator extends \yii\validators\Validator {

    /**
     * {@inheritdoc}
     */
    public function init() {
        parent::init();
        if ($this->message === null) {
            $this->message = '{attribute}格式不正确';
        }
    }

    /**
     * {@inheritdoc}
     */
    public function validateAttribute($model, $attribute) {
        if (!$this->isIdcardNumber($model->$attribute)) {
            $this->addError($model, $attribute, $this->message);
            return;
        }
        parent::validateAttribute($model, $attribute);
    }

    /**
     * {@inheritdoc}
     */
    protected function validateValue($value) {
        return $this->isIdcardNumber($value) ? null : [$this->message, []];
    }

    /**
     * @param mixed $value the data value to be checked.
     */
    private function isIdcardNumber($value) {
        $provinceNumber = array(
            '11', '12', '13', '14', '15', '21', '22',
            '23', '31', '32', '33', '34', '35', '36',
            '37', '41', '42', '43', '44', '45', '46',
            '50', '51', '52', '53', '54', '61', '62',
            '63', '64', '65', '71', '81', '82', '91'
        );
        if (!preg_match('/^([\d]{17}[xX\d]|[\d]{15})$/', $value)) {
            return false;
        }
        if (!in_array(substr($value, 0, 2), $provinceNumber)) {
            return false;
        }
        $value = preg_replace('/[xX]$/i', 'a', $value);
        $length = strlen($value);
        if ($length == 18) {
            $birthday = substr($value, 6, 4) . '-' . substr($value, 10, 2) . '-' . substr($value, 12, 2);
        } else {
            $birthday = '19' . substr($value, 6, 2) . '-' . substr($value, 8, 2) . '-' . substr($value, 10, 2);
        }
        if (date('Y-m-d', strtotime($birthday)) != $birthday) {
            return false;
        }
        if ($length == 18) {
            $_sum = 0;
            for ($i = 17; $i >= 0; $i--) {
                $_subs = substr($value, 17 - $i, 1);
                $_sum += (pow(2, $i) % 11) * (($_subs == 'a') ? 10 : intval($_subs, 11));
            }
            if ($_sum % 11 != 1) {
                return false;
            }
        }
        return true;
    }

}
